-module(navmesh_nif).

-define(NIF_APP, enavmesh).

-include_lib("eunit/include/eunit.hrl").
-include("navmesh_nif.hrl").

-export([
    load_navmesh/1,
    path_find/3
]).

-define(DUNGEON_POINTS, [
    {{37.81, 10.00, -7.43},  {42.07, 10.00, 7.89}},
    {{48.20, 10.00, -1.75},  {3.82, 10.00, -7.82}},
    {{36.90, 10.00, 7.47},   {12.02, 9.99, -20.05}},
    {{12.45, 10.00, 3.22},   {-2.77, -0.00, 3.25}},
    {{0.24, 10.00, -14.15},  {-0.78, 10.00, -24.71}},
    {{-15.50, 0.86, 2.55},   {12.47, 10.00, 2.71}},
    {{9.77, 10.00, -20.07},  {12.47, 10.00, 2.71}},
    {{-2.16, 10.00, -26.11}, {18.85, 19.63, -80.35}},
    {{47.69, 10.00, 3.47},   {21.00, 14.95, -88.66}},
    {{24.53, 15.48, -79.02}, {12.89, 24.75, -82.77}},
    {{23.05, 24.24, -84.66}, {12.89, 24.75, -82.77}},
    {{-3.34, -0.00, 3.90},   {-7.99, -0.00, 1.48}},
    {{24.08, 15.46, -83.25}, {-4.17, 10.00, -27.01}},
    {{24.08, 15.46, -83.25}, {45.09, 10.00, 6.15}},
    {{26.55, 15.85, -82.11}, {-7.50, -0.00, 3.96}}
    ]).


-define(_assertDelta(Expect, Expr), ?_test(?assertDelta(Expect, Expr))).
-define(assertDelta(Expect, Expr),
    begin
        ((fun () ->
            X__X = (Expect),
            ExprV = (Expr),
            case not ExprV - X__X < 0.001 of
                true ->
                    ?assertEqual(X__X, ExprV);
                _ ->
                    ok
            end
          end)())
    end).

-on_load(init/0).

init() ->
    load_nif_from_crate(navmesh_nif, 0).


load_nif_from_crate(Crate, Init) ->
    Path = filename:join([code:priv_dir(?NIF_APP), "crates", Crate, Crate]),
    erlang:load_nif(Path, Init).

%% @doc 加载navmesh文件
-spec load_navmesh(binary()) -> {ok, reference()}.
load_navmesh(_NavmeshFile) ->
    erlang:nif_error(nif_not_loaded).

%% @doc 寻路
-spec path_find(Ref, Start, End) -> PathList when
    Ref :: reference(),
    Start :: {number(), number(), number()},
    End :: {number(), number(), number()},
    PathList :: [{number(), number(), number()}].
path_find(_Ref, _From, _To) ->
    erlang:nif_error(nif_not_loaded).

%% @doc 寻路测试
path_test_() ->
    Ref = load_navmesh(<<"dungeon.bin">>),
    Fun =
        fun({Start, End}) ->
            Path = path_find(Ref, Start, End),
            io:format("Start ~w End ~w Path ~w ~n~n", [Start, End, Path])
        end,
    lists:foreach(Fun, ?DUNGEON_POINTS),
    ok.


%%ntime() ->
%%    {A, B, C} = erlang:timestamp(),
%%    A * 1000000000000 + B * 1000000 + C.

%%move_navigator_test() ->
%%    Ref = load_navmesh(<<"dungeon.bin">>),
%%    SpawnPos = {548.26666, 325.33334}, % 出生点
%%    {SpawnPosX, SpawnPosY} = SpawnPos,
%%    DestPos = {620.8, 205.86668}, % 目标点
%%    Time = ntime(),
%%    Path = path_find(Ref, SpawnPos, DestPos),
%%    io:format("Path ~p ~n", [Path]),
%%    {MeshSizeX, MeshSizeY} = {1024, 768},
%%    Factor = 0.9375,
%%    {PosX, PosY} = {(SpawnPosX - MeshSizeX / 2.0) *Factor, (SpawnPosY - MeshSizeY / 2.0) * Factor},
%%    io:format("PosX, PosY ~p ~n", [{PosX, PosY}]),
%%    Fun =
%%        fun() ->
%%            test_move_navigator_loop(Time, PosX, PosY, Path)
%%        end,
%%    Pid = erlang:spawn(Fun),
%%    timer:send_interval(100, Pid, update),
%%    ok.

%%normalize_pos(PosX, PosY) ->
%%    Len = math:sqrt(PosX * PosX + PosY * PosY),
%%    LengthRecip = 1.0 / Len,
%%    {PosX * LengthRecip, PosY * LengthRecip}.


%%test_move_navigator_loop(Time, PosX, PosY, [Path | LeftPath]) ->
%%    receive
%%        update ->
%%            Factor = 0.9375,
%%            Speed = 100,
%%            NowTime = ntime(),
%%            TimeDiff = NowTime - Time,
%%            case TimeDiff < 0 of
%%                true ->
%%                    io:format("TimeDiff ~p NowTime ~p Time ~p ~n", [TimeDiff, NowTime, Time]),
%%                    test_move_navigator_loop(Time, PosX, PosY, [Path | LeftPath]);
%%                _ ->
%%                    TimeDiffSec = TimeDiff / 1000000,
%%                    {MeshSizeX, MeshSizeY} = {1024, 768},
%%                    {PathX, PathY} = Path,
%%                    {NextX, NextY} = Next = {(PathX - MeshSizeX / 2.0) *Factor, (PathY - MeshSizeY / 2.0) * Factor},
%%                    {TowardX, TowardY} = Toward = {NextX - PosX, NextY - PosY},
%%                    Len = math:sqrt(TowardX * TowardX + TowardY * TowardY),
%%                    {NorTowardX, NorTowardY} = normalize_pos(TowardX, TowardY),
%%                    {AddPosX, AddPosY} = {TimeDiffSec * NorTowardX * Speed, TimeDiffSec * NorTowardY * Speed},
%%                    {NewPosX, NewPosY} = {PosX + AddPosX, PosY + AddPosY},
%%                    io:format("NewPos ~p~n", [{NewPosX, NewPosY}]),
%%%%                    io:format("Path ~p Next ~p Toward ~p TimeDiffSec ~p Pos ~p NewPos ~p NorNor ~p ~n", [Path, Next, Toward, TimeDiffSec, {PosX, PosY}, {NewPosX, NewPosY}, {NorTowardX, NorTowardY}]),
%%                    case Len < TimeDiffSec * Speed of
%%                        true ->
%%                            case LeftPath of
%%                                [_ | _] ->
%%                                    io:format("==================== reached next step ~n"),
%%                                    test_move_navigator_loop(NowTime, NewPosX, NewPosY, LeftPath);
%%                                _ ->
%%                                    io:format("============= reached target ~n")
%%                            end;
%%                        _ ->
%%                            test_move_navigator_loop(NowTime, NewPosX, NewPosY, [Path | LeftPath])
%%                    end
%%            end
%%    end.

